<template>
  <div
    ref="containerRef"
    v-loading="!vLoading"
    class="w-full h-full rounded bg-white px-4"
  >
    <!--    <el-auto-resizer>-->
    <!--      <template #default="{ height }">
      :height="height - 1"-->
    <vxe-grid
      v-show="vLoading"
      ref="vxeGridRef"
      v-bind="gridOptions"
      round
      show-overflow
      show-header-overflow
      header-row-class-name="text-[14px]"
      :height="height"
      v-on="gridEvents"
    >
      <template #toolbar_buttons>
        <!--              <BtnList :action-list="topActions" circle @action-click="actionClick" />-->
        <div v-if="tableTitle" class="pl-2 text-[15px] font-bold">
          <el-icon :size="20" class="inline-block align-middle">
            <!--                <TableIcon />-->
          </el-icon>
          <span>{{ tableTitle }}</span>
        </div>
        <div class="flex-grow overflow-hidden">
          <slot name="topWrap" />
        </div>
        <div v-if="topActions.length > 0">
          <BtnList
            :action-list="topActions"
            circle
            @action-click="actionClick"
          />
        </div>
      </template>
      <!--            表格列插槽-->
      <template v-for="slotKey in defaultSlotList" v-slot:[slotKey]="{ row }">
        <slot :name="slotKey" :row="row" />
      </template>

      <template #empty>
        <div class="flex flex-col items-center justify-center">
          <!--              <img :src="emptyImg" alt="" />-->
          <div>{{ $t("table.noContent") }}</div>
        </div>
      </template>
      <!--          :action-list="handleOperateRow(row, operateActions)"-->
      <template #action_default="{ row }">
        <BtnList
          :action-list="operateActions"
          :row="row"
          link
          @action-click="actionClick($event, row)"
        />
      </template>
    </vxe-grid>
    <!--      </template>-->
    <!--    </el-auto-resizer>-->
  </div>
</template>

<script lang="ts">
import {
  defineComponent,
  nextTick,
  onMounted,
  reactive,
  ref,
  watch
} from "vue";
import {
  VxeGridInstance,
  VxeGridListeners,
  VxeGridProps,
  VxePagerEvents,
  VxeTableEvents
} from "vxe-table";
import { useI18n } from "vue-i18n";

import {
  propsDefinition,
  topActionList,
  operateList,
  handleColumnMap,
  dataPageHandle,
  actionPrevClick,
  handleEmptyData,
  handleVal
} from "./tools";
import { ACTION_TYPE, ActionsProps, ObjectProps } from "../type";
// import TableIcon from "@/assets/svg/table/form.svg?component";
import { isFunction } from "@pureadmin/utils";
import BtnList from "./btnList.vue";
import { VxePagerDefines } from "vxe-table";
import exportExcel from "@/utils/exportExcel";
import { useRoute } from "vue-router";
import { cloneDeep } from "lodash-unified";
// import emptyImg from "@/assets/imgs/No-content.png";

export default defineComponent({
  name: "NbVxeTable",
  components: {
    BtnList
    // TableIcon
  },
  props: propsDefinition,
  emits: [
    "actionClick",
    "currentChange",
    "pageChange",
    "checkboxChange",
    "checkboxAll"
  ],
  setup(props, { slots, emit }) {
    const { te, t, locale } = useI18n();
    // const langList = computed(() => useConfigHook().getLabelList);

    const defaultSlotList = ref([]);
    const serverPage = ref(false);
    const serverData = ref([]);
    const serverOriginData = ref([]);
    const height = ref(560);
    const vLoading = ref(false);
    const containerRef = ref();
    const route = useRoute();

    const gridOptions = reactive<VxeGridProps<{ [key: string]: any }>>({
      border: "none",
      loading: false,
      size: "medium",
      stripe: true,
      // autoResize: true,
      rowConfig: {
        isHover: true,
        isCurrent: true
      },
      columnConfig: {
        resizable: false
      },
      pagerConfig: {
        enabled: true,
        currentPage: 1,
        pageSize: 20,
        total: 0,
        layouts: [
          "Home",
          "PrevJump",
          "PrevPage",
          "Number",
          "NextPage",
          "NextJump",
          "End",
          "Sizes",
          "FullJump",
          "Total"
        ]
      },
      toolbarConfig: {
        // refresh: true,
        // zoom: true,
        // custom: true,
        slots: {
          // 自定义插槽模板
          buttons: "toolbar_buttons"
        }
      },
      sortConfig: {
        trigger: "cell"
      },
      columns: [],
      ...props.vxeTableConfig
    });

    const topActions = ref<ActionsProps[]>([]);
    const operateActions = ref<ActionsProps[]>([]);
    // 用来重置的时候
    const refreshFlag = ref(false);

    const vxeGridRef = ref<VxeGridInstance<ObjectProps>>();

    /* region 组件内置事件****************************************/
    /**
     * A function that handles the click action for a given item.
     *
     * @param {ActionsProps} item - The item containing the action to be clicked.
     * @param {ObjectProps} row - Optional row object associated with the item.
     * @return {Promise<void>} Promise that resolves after handling the click action.
     */
    const actionClick = async (item: ActionsProps, row: ObjectProps = {}) => {
      if (item.onClick && isFunction(item.onClick)) {
        const ret = await item.onClick(row, vxeGridRef);
        ret && emit("actionClick", { ...item, row }, ret);
      } else {
        const res = await actionPrevClick(item.key as ACTION_TYPE);
        if (res) {
          emit("actionClick", { ...item, row });
        }
      }
    };

    const findPageList = async (
      currentPage: number,
      pageSize: number,
      args: any[]
    ) => {
      const queryFetch = props.fetchConfig.query.service;
      let queryParam = props.fetchConfig.query.param;
      if (isFunction(queryParam)) {
        queryParam = queryParam();
      }
      if (args.length) {
        for (const arg of args) {
          queryParam = { ...queryParam, ...arg };
        }
      }
      if (serverPage.value) {
        Object.assign(queryParam, {
          start_page: currentPage,
          size: pageSize
        });
      } else {
        Object.assign(queryParam, {
          size: 0,
          start_page: 1
        });
      }
      const list = await queryFetch(queryParam);
      serverOriginData.value = cloneDeep(list.data);
      serverData.value = list.data.map((v, i) => {
        v.index = i + 1;
        return v;
      });
      let cIndex = currentPage;
      const total = serverPage.value ? list.pageCount : list.data.length;
      // 处理分页大于数据的情况
      if (refreshFlag.value) {
        cIndex = Math.ceil(total / pageSize);
        cIndex = currentPage < cIndex ? currentPage : cIndex;
        refreshFlag.value = false;
      }
      checkboxChange(true);
      return {
        page: {
          total
        },
        result: serverPage.value
          ? handleEmptyData(list.data)
          : handleEmptyData(list.data).slice(
              (cIndex - 1) * pageSize,
              cIndex * pageSize
            )
      };
    };

    /* endregion ****************************************/

    /**
     * 初始化查看传入使用query 还是直接用data
     */
    const useDataOrServer = () => {
      if (props.fetchConfig && isFunction(props.fetchConfig.query?.service)) {
        gridOptions.proxyConfig = {
          seq: true, // 启用动态序号代理（分页之后索引自动计算为当前页的起始序号）
          props: {
            result: "result",
            total: "page.total"
          },
          autoLoad: true, // 是否自动加载
          ajax: {
            // 接收 Promise
            query: ({ page }, ...args) => {
              return findPageList(page.currentPage, page.pageSize, args);
            }
          }
        };
      } else {
        gridOptions.pagerConfig.total = props.dataSource.length;
        if (props.dataSource.length) {
          handlePageChange({
            currentPage: 1,
            pageSize: gridOptions.pagerConfig.pageSize
          } as VxePagerDefines.PageChangeEventParams);
        }
      }

      nextTick(() => {
        checkboxChange(true);
      });
    };

    /**
     * 计算给定文本在特定字体和字号下的宽度
     * 此函数通过创建一个隐藏的 div 元素，设置其字体和字号，然后测量其宽度来实现
     * 这种方法用于在不显示文本的情况下，准确地计算文本的渲染宽度
     *
     * @param text 需要计算宽度的文本
     * @param fontFamily 文本的字体家族
     * @param fontSize 文本的字号
     * @returns number 文本的宽度，返回值包括一些额外的宽度以模拟实际渲染效果
     */
    function calculateWidth(
      text: string,
      fontFamily: string,
      fontSize: string
    ) {
      // 创建一个隐藏的 div 元素
      const hiddenDiv = document.createElement("div");
      hiddenDiv.className = "hidden-div";
      hiddenDiv.style.fontFamily = fontFamily;
      hiddenDiv.style.fontSize = fontSize;
      hiddenDiv.textContent = text;

      // 将隐藏的 div 添加到文档中
      document.body.appendChild(hiddenDiv);

      // 获取隐藏 div 的宽度
      const width = hiddenDiv.offsetWidth;

      // 从文档中移除隐藏的 div
      document.body.removeChild(hiddenDiv);

      return width;
    }

    function exportHandle(action: ACTION_TYPE[]) {
      if (!action.includes(ACTION_TYPE.DOWNLOAD) && props.showExportBtn) {
        const exportCase = {
          icon: "table-Export",
          key: ACTION_TYPE.DOWNLOAD,
          seq: 50,
          name: "table.export",
          onClick: () => {
            // exportExcel(
            //   gridOptions.columns,
            //   props.dataSource.length ? props.dataSource : serverData.value,
            //   route.meta.title
            // );
            const $table = vxeGridRef.value;
            console.log(serverOriginData.value);
            $table.exportData({
              filename:
                (te(route.meta.title)
                  ? t(route.meta.title)
                  : route.meta.title) + "导出数据",
              type: "xlsx",
              original: false,
              data: serverOriginData.value.map((v, i) => {
                v.index = i + 1;
                return v;
              }),
              isHeader: true,
              columnFilterMethod({ column }) {
                if (column.property === "action" || column.type === "checkbox")
                  return false;
                return true;
              }
            });
          }
        };
        topActions.value.push(exportCase);
      }
    }

    /**
     * Get the action list based on the provided props.
     */
    const getActionList = () => {
      const topActList = topActionList.filter(v =>
        props.actions.includes(v.key as ACTION_TYPE)
      );
      topActions.value = [...topActList, ...props.topTools].sort(
        (a, b) => a.seq - b.seq
      );

      exportHandle(props.actions);

      const operList = operateList.filter(v =>
        props.actions.includes(v.key as ACTION_TYPE)
      );
      operateActions.value = [...operList, ...props.operateTools].sort(
        (a, b) => a.seq - b.seq
      );

      const fontLength = operateActions.value.reduce((pre, cur) => {
        return pre + t(cur.name);
      }, "");

      const width = calculateWidth(fontLength, "inherit", "14px");
      console.log(width);
      if (operateActions.value.length > 0) {
        const operateWidth = width + 17 * operateActions.value.length + 30;
        if (gridOptions.columns.find(v => v.field === "action")) {
          gridOptions.columns = gridOptions.columns.filter(
            v => v.field !== "action"
          );
        }
        gridOptions.columns.push({
          field: "action",
          title: t("table.action"),
          fixed: "right",
          width: operateWidth,
          slots: { default: "action_default" },
          showOverflow: false,
          ...(props.vxeColumnConfig?.action || {})
        });
      } else {
        gridOptions.columns = gridOptions.columns.filter(
          v => v.field !== "action"
        );
      }
    };

    /**
     * Loop through slotName keys and push keys ending with "_default" to defaultSlotList.
     *
     */
    const getColumnSlot = () => {
      for (const slotNameKey in slots) {
        if (slotNameKey.endsWith("_default")) {
          defaultSlotList.value.push(slotNameKey);
        }
      }
    };

    /**
     * Generates the columns data based on props and updates the gridOptions.
     */
    const columnsProcess = () => {
      if (!props.columns || !props.columns.length) return;
      const columnsData = handleColumnMap(
        props.columns,
        props.vxeColumnConfig,
        { t, te }
      );
      if (props.showIndex) {
        // columnsData.unshift({ type: "seq", width: 60, align: "center" });
        columnsData.unshift({
          field: "index",
          title: t("table.index"),
          width: 60,
          align: "center"
        });
      }
      if (props.showCheckbox) {
        columnsData.unshift({ field: "check", type: "checkbox", width: 50 });
      }
      // columnsData.push({
      //   field: "none",
      //   title: ""
      // });
      gridOptions.columns = columnsData;
      getActionList();
    };

    const handlePageChange: VxePagerEvents.PageChange = ({
      currentPage,
      pageSize
    }) => {
      checkboxChange(true);
      if (gridOptions.pagerConfig.enabled) {
        gridOptions.pagerConfig.currentPage = currentPage;
        gridOptions.data = dataPageHandle(
          handleEmptyData(props.dataSource),
          currentPage,
          pageSize
        );
        emit("pageChange", { currentPage, pageSize });
      } else {
        gridOptions.data = handleEmptyData(props.dataSource);
      }
    };

    const currentChange: VxeTableEvents.CurrentChange<
      ObjectProps
    > = rowOption => {
      emit("currentChange", rowOption);
    };

    const checkboxChange = (
      isEmpty = false,
      checkParam?: ObjectProps,
      isAll?: boolean
    ) => {
      const list = isEmpty ? [] : vxeGridRef.value.getCheckboxRecords();
      const keys = [
        ACTION_TYPE.TDELETE,
        ACTION_TYPE.TPUTAWAY,
        ACTION_TYPE.TOFFSHELVE
      ];
      for (const key of keys) {
        const i = topActions.value.findIndex(v => v.key === key);
        if (i !== -1) {
          topActions.value[i].disabled = !list.length;
        }
      }
      if (isAll) {
        emit("checkboxAll", list, checkParam);
      } else {
        emit("checkboxChange", list, checkParam);
      }
    };

    const setHeight = () => {
      if (props.height && props.height !== 0) {
        height.value = props.height as number;
      }
      const containerHeight = containerRef.value.clientHeight;
      const otherHeight = 0;
      console.dir(containerRef.value);
      height.value = containerHeight - otherHeight;
      vLoading.value = true;
    };

    const gridEvents: VxeGridListeners<Record<string, any>> = {
      checkboxChange: data => checkboxChange(false, data),
      checkboxAll: data => checkboxChange(false, data, true),
      currentChange,
      pageChange: handlePageChange
    };

    const getCheckboxRecords = (isFull?: boolean) => {
      const list = vxeGridRef.value.getCheckboxRecords(isFull);
      return list.map(val => handleVal(val));
    };

    const refresh = () => {
      refreshFlag.value = true;
      vxeGridRef.value.commitProxy("query");
    };

    watch(() => props.columns, columnsProcess, { immediate: true });
    watch(() => locale.value, columnsProcess); // 监听中英文重新加载
    watch(
      () => props.vxeTableConfig,
      val => {
        Object.assign(gridOptions, val);
      },
      {
        deep: true
      }
    );
    watch(
      () => props.dataSource,
      val => {
        gridOptions.pagerConfig.total = props.dataSource.length;
        serverOriginData.value = cloneDeep(val);
        serverData.value = val.map((v, i) => {
          v.index = i + 1;
          return v;
        });
        handlePageChange({
          currentPage: 1,
          pageSize: gridOptions.pagerConfig.pageSize
        } as VxePagerDefines.PageChangeEventParams);
      },
      {
        deep: true
      }
    );

    watch(
      [() => props.actions, () => props.operateTools, () => props.topTools],
      () => {
        getActionList();
      }
    );

    getColumnSlot();

    onMounted(() => {
      useDataOrServer();
      vLoading.value = false;
      setTimeout(() => {
        setHeight();
      }, 300);
    });

    return {
      gridOptions,
      topActions,
      operateActions,
      defaultSlotList,
      vxeGridRef,
      gridEvents,
      height,
      vLoading,
      containerRef,
      // emptyImg,
      te,
      refresh,
      actionClick,
      getCheckboxRecords
    };
  }
});
</script>
<style lang="scss" scoped>
$borderColor: #fff;

.border-no_bottom {
  border-color: $borderColor;
  border-width: 1px 1px 0;
}

.border-no_top {
  border-color: $borderColor;
  border-width: 0 1px 1px;
}

.border-top {
  border-top: 1px solid $borderColor;
}

.border {
  border: 1px solid $borderColor;
}

:deep(.vxe-pager) {
  border-top: 1px solid $borderColor;
}

:deep(.vxe-table--border-line) {
  border: none;
}

:deep(.vxe-table--render-default .vxe-body--x-space) {
  height: 0;
}
</style>
